﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Runtime.InteropServices;
using System.Text;

namespace SharpSniffer
{
    class StructTest
    {


    }




    /// <summary>
    /// IP包头
    /// </summary>
    public class IPHead
    {
        /// <summary>
        /// 将字节转换成为IP包
        /// </summary>
        /// <param name="arr"></param>
        /// <param name="refObj"></param>
        /// <returns></returns>
        public static IPHead Parse(byte[] arr, IPHead refObj = null)
        {
            if (refObj == null)
            {
                refObj = new IPHead();
            }
            int offset = 0;
            refObj.version = arr[0] >> 4 & 0xf;
            refObj.ihl = arr[0] & 0xf;
            offset++;
            refObj.TypeOrServer = arr[1];
            offset++;
            refObj.tot_len = BitConverter.ToUInt16(arr, offset);
            offset += 2;
            refObj.identifier = BitConverter.ToUInt16(arr, offset);
            offset += 2;
            refObj.flg = arr[offset] >> 4 & 0xf;
            refObj.FragmentedOffset = BitConverter.ToUInt16(arr, offset) & 0xFFF;
            offset += 2;
            refObj.ttl = arr[offset];
            offset++;

            switch (arr[offset])
            {

                //     未指定的协议。	
                case 0: refObj.protocol = System.Net.Sockets.ProtocolType.Unspecified;
                    //	
                    break;				// 摘要:	
                ////     网际协议。	
                //case 0: refObj.protocol = System.Net.Sockets.ProtocolType.IP;
                //    //	
                //    break;
                ////     IPv6 逐跳选项头。	
                //case 0: refObj.protocol = System.Net.Sockets.ProtocolType.IPv6HopByHopOptions;
                //    //	
                //    break;				// 摘要:	
                // 摘要:	
                //     网际消息控制协议。	
                case 1: refObj.protocol = System.Net.Sockets.ProtocolType.Icmp;
                    //	
                    break;				// 摘要:	
                //     网际组管理协议。	
                case 2: refObj.protocol = System.Net.Sockets.ProtocolType.Igmp;
                    //	
                    break;				// 摘要:	
                //     网关到网关协议。	
                case 3: refObj.protocol = System.Net.Sockets.ProtocolType.Ggp;
                    //	
                    break;				// 摘要:	
                //     Internet Protocol version 4.	
                case 4: refObj.protocol = System.Net.Sockets.ProtocolType.IPv4;
                    //	
                    break;				// 摘要:	
                //     传输控制协议。	
                case 6: refObj.protocol = System.Net.Sockets.ProtocolType.Tcp;
                    //	
                    break;				// 摘要:	
                //     PARC 通用数据包协议。	
                case 12: refObj.protocol = System.Net.Sockets.ProtocolType.Pup;
                    //	
                    break;				// 摘要:	
                //     用户数据报协议。	
                case 17: refObj.protocol = System.Net.Sockets.ProtocolType.Udp;
                    //	
                    break;				// 摘要:	
                //     Internet 数据报协议。	
                case 22: refObj.protocol = System.Net.Sockets.ProtocolType.Idp;
                    //	
                    break;				// 摘要:	
                //     Internet 协议版本 6 (IPv6)。	
                case 41: refObj.protocol = System.Net.Sockets.ProtocolType.IPv6;
                    //	
                    break;				// 摘要:	
                //     IPv6 路由头。	
                case 43: refObj.protocol = System.Net.Sockets.ProtocolType.IPv6RoutingHeader;
                    //	
                    break;				// 摘要:	
                //     IPv6 片段头。	
                case 44: refObj.protocol = System.Net.Sockets.ProtocolType.IPv6FragmentHeader;
                    //	
                    break;				// 摘要:	
                //     IPv6 封装式安全措施负载头。	
                case 50: refObj.protocol = System.Net.Sockets.ProtocolType.IPSecEncapsulatingSecurityPayload;
                    //	
                    break;				// 摘要:	
                //     IPv6 身份验证头。有关详细信息请参见位于 http://www.ietf.org 中的 RFC 2292 的 2.2.1 节。	
                case 51: refObj.protocol = System.Net.Sockets.ProtocolType.IPSecAuthenticationHeader;
                    //	
                    break;				// 摘要:	
                //     用于 IPv6 的 Internet 控制消息协议。	
                case 58: refObj.protocol = System.Net.Sockets.ProtocolType.IcmpV6;
                    //	
                    break;				// 摘要:	
                //     IPv6 No Next 头。	
                case 59: refObj.protocol = System.Net.Sockets.ProtocolType.IPv6NoNextHeader;
                    //	
                    break;				// 摘要:	
                //     IPv6 目标选项头。	
                case 60: refObj.protocol = System.Net.Sockets.ProtocolType.IPv6DestinationOptions;
                    //	
                    break;				// 摘要:	
                //     网络磁盘协议（非正式）。	
                case 77: refObj.protocol = System.Net.Sockets.ProtocolType.ND;
                    //	
                    break;				// 摘要:	
                //     原始 IP 数据包协议。	
                case 255: refObj.protocol = System.Net.Sockets.ProtocolType.Raw;
                    //	
                    break;				// 摘要:	
                ////     Internet 数据包交换协议。	
                //case 1000: refObj.protocol = System.Net.Sockets.ProtocolType.Ipx;
                //    //	
                //    break;				// 摘要:	
                ////     顺序包交换协议。	
                //case 1256: refObj.protocol = System.Net.Sockets.ProtocolType.Spx;
                //    //	
                //    break;				// 摘要:	
                ////     顺序包交换协议第 2 版。	
                //case 1257: refObj.protocol = System.Net.Sockets.ProtocolType.SpxII;
                //    break;

            }

            offset++;
            refObj.chk_sum = BitConverter.ToInt16(arr, offset);
            offset += 2;
            refObj.srcaddr = new IPAddress(arr.Skip(offset).Take(4).ToArray());
            offset += 4;
            refObj.dstaddr = new IPAddress(arr.Skip(offset).Take(4).ToArray());
            offset += 4;

            return refObj;
        }



        /// <summary>
        /// 版本
        /// </summary>
        public int version;
        /// <summary>
        /// 首部长度,IP包长度 * 4 (包含多少个32位)
        /// </summary>
        public int ihl;
        /// <summary>
        /// 服务类型
        /// </summary>
        public byte TypeOrServer;
        /// <summary>
        /// 总长度
        /// </summary>
        public ushort tot_len;
        /// <summary>
        /// 标志
        /// </summary>
        public ushort identifier;
        /// <summary>
        /// 标识
        /// </summary>
        public int flg;
        /// <summary>
        /// 分片偏移
        /// </summary>
        public int FragmentedOffset;
        /// <summary>
        /// 生存时间
        /// </summary>
        public byte ttl;
        /// <summary>
        /// 协议
        /// </summary>
        public System.Net.Sockets.ProtocolType protocol;
        /// <summary>
        /// 检验和
        /// </summary>
        public short chk_sum;
        /// <summary>
        /// 源IP地址   4 字节
        /// </summary>
        public IPAddress srcaddr;
        /// <summary>
        /// 目的IP地址    4 字节
        /// </summary>
        public IPAddress dstaddr;

    }


    /// <summary>
    /// TCP包
    /// </summary>
    public class TCPPackeg
    {
        //TCP头部，总长度20字节  


        private static byte[] defaultdata = new byte[0];

        /// <summary>
        /// 构造一个新的TCP包数据体
        /// </summary>
        /// <param name="arr">数组</param>
        /// <param name="offset">偏移量默认20</param>
        /// <param name="refObj">引用对像</param>
        /// <returns></returns>
        public static TCPPackeg Parse(byte[] arr, int offset = 20,int maxLen=40, TCPPackeg refTCPPackeg = null)
        {
            //开始偏移量
            int startOffset = offset;

            if (refTCPPackeg == null)
            {
                refTCPPackeg = new TCPPackeg();
            }

            refTCPPackeg.src_port = BitConverter.ToUInt16(new byte[] { arr[offset + 1], arr[offset] }, 0);
            offset += 2;
            refTCPPackeg.dst_port = BitConverter.ToUInt16(new byte[] { arr[offset + 1], arr[offset] }, 0);
            offset += 2;
            refTCPPackeg.seq_no = BitConverter.ToUInt16(arr, offset);
            offset += 4;
            refTCPPackeg.ack_no = BitConverter.ToUInt16(arr, offset);
            offset += 4;
            refTCPPackeg.thl = arr[offset] >> 4 & 0xf;
            refTCPPackeg.reserved_1 = arr[offset] & 0xf;
            offset++;
            refTCPPackeg.reseverd_2 = arr[offset] >> 6 & 0x3;
            refTCPPackeg.flag = arr[offset] & 0x3f;
            offset++;
            refTCPPackeg.wnd_size = BitConverter.ToInt16(new byte[] { arr[offset + 1], arr[offset] }, 0);
            offset += 2;
            refTCPPackeg.chk_sum = BitConverter.ToInt16(new byte[] { arr[offset + 1], arr[offset] }, 0);
            offset += 2;
            refTCPPackeg.urgt_p = BitConverter.ToInt16(new byte[] { arr[offset + 1], arr[offset] }, 0);
            offset += 2;

            int len = refTCPPackeg.thl * 4;
            //数据长度
            int dataLen = maxLen - startOffset - len;

            if (dataLen > 0)
            {
                byte[] tempdata = new byte[dataLen];
                Buffer.BlockCopy(arr, startOffset + len, tempdata, 0, dataLen);
                refTCPPackeg.TCPData = tempdata;
            }
            else
            {
                refTCPPackeg.TCPData = defaultdata;
            }




            return refTCPPackeg;

        }

        /// <summary>
        /// 来源端口号
        /// </summary>
        public ushort src_port;
        /// <summary>
        /// 目的端口号
        /// </summary>
        public ushort dst_port;
        /// <summary>
        /// 序列号
        /// </summary>
        public int seq_no;
        /// <summary>
        /// 确认号
        /// </summary>
        public int ack_no;

        /// <summary>
        ///  tcp头部长度   4bit   TCP包长度 * 4 (包含多少个32位)
        /// </summary>
        public int thl;
        /// <summary>
        ///保留6位中的4位首部长度    4bit
        /// </summary>
        public int reserved_1;
        /// <summary>
        /// 保留6位中的2位    2bit
        /// </summary>
        public int reseverd_2;
        /// <summary>
        /// 6位标志     6bit
        /// </summary>
        public int flag;



#if LITTLE_ENDIAN  
         //char reserved_1 : 4; //保留6位中的4位首部长度  
         //char thl : 4;        //tcp头部长度  
         //char flag : 6;       //6位标志  
         //char reseverd_2 : 2; //保留6位中的2位  
#else
#endif
        /// <summary>
        /// 16位窗口大小  
        /// </summary>
        public short wnd_size;
        /// <summary>
        /// 16位TCP检验和  
        /// </summary>
        public short chk_sum;
        /// <summary>
        /// 16为紧急指针  
        /// </summary>
        public short urgt_p;

        /// <summary>
        /// TCP包数据
        /// </summary>
        public byte[] TCPData { get; set; }
    }

    /// <summary>
    /// UDP头部，总长度8字节  
    /// </summary>

    public class UDPPackeg
    {

        private static byte[] defaultdata = new byte[0];
        /// <summary>
        /// 构造一个UDP数据包
        /// </summary>
        /// <param name="arr">原始数据</param>
        /// <param name="offset">依稀量</param>
        /// <param name="refUDPackeg">引用的UDP包</param>
        /// <returns></returns>

        public static UDPPackeg Parse(byte[] arr, int offset = 20, UDPPackeg refUDPackeg = null)
        {

            if (refUDPackeg == null)
            {
                refUDPackeg = new UDPPackeg();
            }

            refUDPackeg.src_port = BitConverter.ToUInt16(new byte[] { arr[offset + 1], arr[offset] }, 0);
            offset += 2;
            refUDPackeg.dst_port = BitConverter.ToUInt16(new byte[] { arr[offset + 1], arr[offset] }, 0);
            offset += 2;
            refUDPackeg.UdpLength = BitConverter.ToUInt16(new byte[] { arr[offset + 1], arr[offset] }, 0);
            offset += 2;
            refUDPackeg.chk_sum = BitConverter.ToInt16(new byte[] { arr[offset + 1], arr[offset] }, 0);
            offset += 2;

            //UDP数据长度
            int datlen= refUDPackeg.UdpLength-8;

            if (arr.Length >= offset + datlen)
            {
                byte[] tempdata = new byte[datlen];
                Buffer.BlockCopy(arr, offset, tempdata, 0, datlen);
                refUDPackeg.UDPData = tempdata;
            }
            else
            {
                //这个是错误的
                //var len = arr.Length - offset;
                //byte[] tempdata = new byte[len];
                //Buffer.BlockCopy(arr, offset, tempdata, 0, len);
                //refUDPackeg.UDPData = tempdata;
                refUDPackeg.UDPData = defaultdata;
            }


            return refUDPackeg;

        }

        public ushort src_port; //远端口号  
        /// <summary>
        /// 目的端口号  
        /// </summary>
        public ushort dst_port;
        /// <summary>
        /// udp头部长度  
        /// </summary>
        public ushort UdpLength;
        /// <summary>
        /// 16位udp检验和  
        /// </summary>
        public short chk_sum;

        /// <summary>
        /// UDP包数据
        /// </summary>
        public byte[] UDPData { get; set; }

    }
}
